package com.google.code.pokerstats_service.math;

import edu.uci.ics.jung.algorithms.scoring.PageRank;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.util.Pair;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections15.TransformerUtils;

import com.google.code.pokerstats_service.Game;
import com.google.code.pokerstats_service.PlayerResult;
import com.google.code.pokerstats_service.PlayerStats;

/**
 * Calculates players' PokerRank scores.
 * 
 * @author DL
 */
public class PokerRankCalculator {
    
    public void updateStats(
	    Map<Game, Set<PlayerResult>> games, Map<Long, PlayerStats> playersStats) {
	
        // Create money transfers map
        Map<Pair<Long>,Double> payments = new HashMap<Pair<Long>,Double>();
        for (Game game : games.keySet()) {
            // Extract prize winners
            double gameTotalPrizes = 0;
            Map<Long, Double> prizeWinners = new HashMap<Long, Double>();
            for (PlayerResult playerResult : games.get(game)) {
                if (playerResult.cashOut > 0) {
                    gameTotalPrizes += playerResult.cashOut;
                    prizeWinners.put(playerResult.player, playerResult.cashOut);
                }
            }
            
            // Update money transfers map
            for (PlayerResult playerResult : games.get(game)) {
                for (Long prizeWinner : prizeWinners.keySet()) {
                    double payment =
                	playerResult.buyIn * prizeWinners.get(prizeWinner) / gameTotalPrizes;
                    
                    Pair<Long> link = new Pair<Long>(playerResult.player, prizeWinner);
                    if (!payments.containsKey(link)) {
                        payments.put(link, payment);
                    } else {
                        payments.put(link, payments.get(link) + payment);
                    }
                }
            }
        }
        
        // Create payments graph (and normalize money transfers map)
        DirectedGraph<Long, Pair<Long>> paymentsGraph =
            new DirectedSparseGraph<Long, Pair<Long>>();
        
        for (Pair<Long> link : payments.keySet()) {
            payments.put(link, payments.get(link) /
                playersStats.get(link.getFirst()).totalBuyIns);
            
            paymentsGraph.addEdge(link, link.getFirst(), link.getSecond());
        }
        
        // Calculate PokerRank
        PageRank<Long, Pair<Long>> ranker = new PageRank<Long, Pair<Long>>(
            paymentsGraph, TransformerUtils.mapTransformer(payments), 0.2);
        ranker.evaluate();
        
        for (PlayerStats playerStats : playersStats.values()) {
            playerStats.pokerRank = ranker.getVertexScore(playerStats.fbUid);
        }
    }
}
